home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
9-Digit Zip Code Directory
/
9-Digit Zip Code Directory (American Business Information) (ABIZIP-12).ISO
/
z4src.zip
/
CPNYBBLE.C
< prev
next >
Wrap
C/C++ Source or Header
|
1993-07-07
|
9KB
|
321 lines
//----------------------------------------------------------------------------
// MODULE DESCRIPTION
//
// Module: cbnybble.c
// Title: Data Compression Library
// Notice: John M. Weeder
// Copyright (c) 1993. All rights reserved.
// This module contains proprietary information and should be
// treated as confidential.
//
//----------------------------------------------------------------------------
// MAINTENANCE HISTORY
//
// $Workfile$
// $Revision$
// $Author$
// $Date$
// $Log$
//
//----------------------------------------------------------------------------
// MODULE NARRATIVE
//
//
// This module contains code to encode a string on a nybble by nybble basis.
//
// Note the 0x80 bit of the first byte in a nybble encoded string is never
// set. This differentiates a nybble encoded string from a cached word.
//
// The code in this module should be written entirely in C.
// Do not use any C++ constructs.
//
// This module is portable to:
// DOS 3.X+
// MS Windows 3.X+
// OS/2 2.X+
// OS/2 2.0 PM
// SCO UNIX.
//
// The following compilers are supported:
// MSC 6.0A
// MSC/C++ 7.0
// Borland C++ 3.1 for DOS
// Borland C++ 1.0 for OS/2 2.X
// SCO UNIX cc
//
//----------------------------------------------------------------------------
#include <cp.h>
//----------------------------------------------------------------------------
// Compression tables
// Order of characters within each level is important to search speed while
// encoding.
//----------------------------------------------------------------------------
static CHAR achLevel1[15] = // These characters are stored in 1 nybble
{
'E',
'A',
'O',
'I',
'U',
'S',
'T',
'R',
'L',
'N',
'D',
'M',
'C',
'P',
'H',
};
static CHAR achLevel2[15] = // These characters are stored in 2 nybbles
{ // All others are stored in 3 nybbles
'F',
'B',
'W',
'Y',
'K',
'G',
'V',
'J',
'X',
'Q',
'Z',
'-',
'/',
'#',
'&'
};
//----------------------------------------------------------------------------
// Macros
//----------------------------------------------------------------------------
//
// Macro to read a nybble from the byte stream
//
#define NybbleInput() if (fNybble) \
{ \
bVal = (BYTE)((*pbDecode) & 0x0F); \
pbDecode++; \
} \
else \
{ \
bVal = (BYTE)((*pbDecode) >> 4); \
cDecode++; \
} \
fNybble = !fNybble;
//
// Macro to write a nybble to the byte stream
//
#define NybbleOutput() if (fNybble) \
{ \
*pbEncode |= bVal; \
pbEncode++; \
} \
else \
{ \
*pbEncode = (BYTE)(bVal << 4); \
cEncode++; \
} \
fNybble = !fNybble;
//----------------------------------------------------------------------------
// Description: Decode a buffer
// Parameters: pbDecode Pointer to buffer to decode.
// pcDecode Pointer to receive number of bytes decoded.
// pch Buffer to place decoded text into.
// Null terminator is added to buffer.
// Buffer is assumed to be of sufficient size.
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_E NybbleDecode(PBYTE pbDecode, PSIZET pcDecode, PCHAR pch)
{
SIZET cChars;
SIZET cDecode = 0;
BOOL fNybble = FALSE;
BYTE bVal;
Assert(pbDecode && pcDecode && pch);
Assert(*pbDecode && *pbDecode <= 0x7F);
if (*pbDecode == 0x7F) // Unencoded ASCII string!
{
strcpy(pch, (PSZ)(pbDecode + 1));
*pcDecode = strlen((PSZ)(pbDecode + 1)) + 2;
return TRUE;
}
cChars = (SIZET)*pbDecode; // Check decode length
pbDecode++;
cDecode++;
for (; cChars; cChars--)
{
NybbleInput();
if (bVal)
{
*pch++ = achLevel1[bVal-1];
}
else
{
NybbleInput();
if (bVal) // Input a 1 byte character
{
*pch++ = achLevel2[bVal-1];
}
else
{
NybbleInput(); // Input a 2 byte character
*pch = (CHAR)(BYTE)(bVal << 4);
NybbleInput();
*pch |= bVal;
pch++; // Move to next
}
}
}
*pcDecode = cDecode;
pch[0] = '\0'; // Add null terminator
return TRUE;
}
//----------------------------------------------------------------------------
// Description: Encode a buffer
// The first byte contains the length of the encoded string.
// This length must be < 0x7F, since the 0x80 bit may not
// be set.
// If the length is 0x7F, the string is not encoded, but is
// stored as an ASCII zero terminated string. This is done
// because the encoded string took more space than the
// un-encoded string.
// Parameters: pbEncode Pointer to buffer to encode into.
// pcEncode Pointer to variable to recieve size of
// encoded text.
// Buffer must be of sufficient size.
// Maximum size is strlen(pcsz)+2.
// pcsz Buffer to read text from.
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
BOOL FN_E NybbleEncode(PBYTE pbEncode, PSIZET pcEncode, PCSZ pcsz)
{
SIZET cEncode = 1;
SIZET i;
BYTE bVal;
BOOL fNybble = FALSE;
SIZET cMaxEncode;
PBYTE pbSave = pbEncode;
PCSZ pcszSave = pcsz;
Assert(pbEncode && pcEncode && pcsz && pcsz[0]);
cMaxEncode = strlen(pcsz);
Assert(cMaxEncode && cMaxEncode < 0x7F);
*pbEncode = (BYTE)cMaxEncode;
pbEncode++;
cMaxEncode += 2;
for (; pcsz[0];)
{ // Try to encode into first level
for (i = 0; i < 15; ++i)
if (achLevel1[i] == pcsz[0])
break;
if (i >= 15)
{
bVal = (BYTE)0;
NybbleOutput();
if (cEncode == cMaxEncode)
break;
for (i = 0; i < 15; ++i) // Encode to second level
if (achLevel2[i] == pcsz[0])
break;
if (i >= 15)
{
bVal = 0; // Level 3 (2 bytes)
NybbleOutput();
if (cEncode == cMaxEncode)
break;
bVal = (BYTE)(pcsz[0] >> 4);
NybbleOutput();
if (cEncode == cMaxEncode)
break;
bVal = (BYTE)(pcsz[0] & 0x0F);
NybbleOutput();
if (cEncode == cMaxEncode)
break;
}
else
{
bVal = (BYTE)(i + 1); // Level 1 (2 nybbles)
NybbleOutput();
if (cEncode == cMaxEncode)
break;
}
}
else
{
bVal = (BYTE)(i + 1); // Level 1 (1 nybble)
NybbleOutput();
if (cEncode == cMaxEncode)
break;
}
pcsz++;
}
if (cEncode >= cMaxEncode)
{
*pbSave = (BYTE)0x7F; // Copy string and null
strcpy((PSZ)(pbSave + 1), pcszSave);
cEncode = cMaxEncode;
}
*pcEncode = cEncode; // Return length of encoded string
return TRUE;
}
//----------------------------------------------------------------------------
// Description: Run standard test suite
// Parameters: sTest Test to run.
// 0 Run all default tests (except).
// Returns: TRUE if successful.
//----------------------------------------------------------------------------
#if COMPILE_TEST
BOOL FN NybbleTest(SHORT sTest)
{
static CHAR szBuf[80];
static BYTE bBuf[80];
static PSZ apsz[] =
{
"EAOIUSTRLNDMCPH", // All nybble
"FBWYKGVJXQZ-/#&", // All byte
"1234567890", // 2 Byte
"E", // Single char
"F", // Single char
"1", // Single char
"EF1B2AB2OWW3IIY4UK5SG6TV7", // A mix
NULL
};
SIZET i;
SIZET cEncode, cDecode;
NOTUSED(sTest);
for (i = 0; apsz[i]; ++i)
{
NybbleEncode(bBuf, &cEncode, apsz[i]);
Output(" Input: (%3d) %s\n", strlen(apsz[i])+1, apsz[i]);
NybbleDecode(bBuf, &cDecode, szBuf);
Output("Output: (%3d) %s\n", strlen(szBuf)+1, szBuf);
Output(" Bytes: %3d\n", cEncode);
if (cEncode != cDecode
|| strcmp(apsz[i], szBuf) != 0)
return FALSE;
}
return TRUE;
}
#endif
//----------------------------------------------------------------------------
//------------------------------- End of File --------------------------------
//----------------------------------------------------------------------------